package url_maping_util

import (
	app_global "app/app_src/framework/app/global"
	app_util "app/app_src/framework/app/util"
	file_util "app/app_src/framework/util/file"
	json_util "app/app_src/framework/util/json"
	"io/fs"
	"strings"
)

// 配置文件的字段
type UrlMappingRule struct {
	// 来源 URL 前缀
	OriginalUrlPrefix string
	// 映射 URL 前缀
	MappedUrlPrefix string
	// 资源路径
	ResourceBasePath string
	// 是否优先映射 min.xx 后缀
	MinSuffixPriority bool
}

// 配置文件的前后缀
const _CONFIG_FILE_PREFIX = "resources/app/config/urlMappingRules-"
const _CONFIG_FILE_SUFFIX = ".json"
const _CONFIG_FILE_DEFAULT = "default"

const _PATH_SUFFIX_DOT = "."
const _PATH_SEPERATOR_BACKSLASH = "/"
const _PATH_SEPERATOR_UNIX = "/"
const _PATH_SEPERATOR_WINDOWS = "\\"

// 获取映射的 URL 信息
func GetMappingUrlMap() map[string]string {
	result := map[string]string{}

	// 读取配置文件的内容
	content := _ReadConfig()
	// 反序列化成结构体
	rules := []UrlMappingRule{}
	json_util.FromString(content, &rules)

	for index := range rules {
		// 添加映射 URL 到结果中
		_AddMappingUrlMap(result, &rules[index])
	}

	return result
}

// 读取配置文件的内容
func _ReadConfig() string {
	embedFS := app_global.EmbedFS()
	env := app_util.GetEnv()

	path := _CONFIG_FILE_PREFIX + env + _CONFIG_FILE_SUFFIX
	content, err := embedFS.ReadFile(path)

	if err != nil {
		path = _CONFIG_FILE_PREFIX + _CONFIG_FILE_DEFAULT + _CONFIG_FILE_SUFFIX
		content, err = embedFS.ReadFile(path)

		if err != nil {
			panic(err)
		}
	}

	return string(content)
}

// 添加映射 URL 到结果中
func _AddMappingUrlMap(result map[string]string, rule *UrlMappingRule) {
	resourceBasePath := rule.ResourceBasePath
	// 获取指定目录下的所有文件路径
	relativePathMap := _GetAllFilePaths(resourceBasePath)

	originalUrlPrefix := rule.OriginalUrlPrefix
	mappedUrlPrefix := rule.MappedUrlPrefix
	minSuffixPriority := rule.MinSuffixPriority

	for relativePath := range relativePathMap {
		originalUrl := _JoinUrl(originalUrlPrefix, relativePath)
		mappedUrl := _JoinUrl(mappedUrlPrefix, relativePath)

		if minSuffixPriority {
			// 获取对应的压缩路径
			minRelativePath := _GetMinSuffxPath(relativePath)

			_, ok := relativePathMap[minRelativePath]
			// 添加 URL 映射
			if ok {
				minMappedUrl := _JoinUrl(mappedUrlPrefix, minRelativePath)
				result[originalUrl] = minMappedUrl
			} else {
				result[originalUrl] = mappedUrl
			}
		} else {
			// 添加 URL 映射
			result[originalUrl] = mappedUrl
		}
	}
}

// 获取指定目录下的所有文件路径
func _GetAllFilePaths(resourceBasePath string) map[string]string {
	dirFS, dirPath := _GetDirInfo(resourceBasePath)
	filePaths := []string{}
	_ScanDir(&filePaths, dirFS, dirPath)

	relativePathMap := map[string]string{}
	basePathLength := len(dirPath)

	for index := range filePaths {
		relativePath := filePaths[index][basePathLength:]
		relativePathMap[relativePath] = filePaths[index]
	}

	return relativePathMap
}

// 获取目录信息
func _GetDirInfo(resourceBasePath string) (fs.ReadDirFS, string) {
	var dirFS fs.ReadDirFS
	// 把 windows 文件路径分隔符替换成 unix 风格
	dirPath := strings.ReplaceAll(resourceBasePath, _PATH_SEPERATOR_WINDOWS, _PATH_SEPERATOR_UNIX)

	if !strings.HasSuffix(dirPath, _PATH_SEPERATOR_UNIX) {
		dirPath = dirPath + _PATH_SEPERATOR_UNIX
	}

	if strings.HasPrefix(dirPath, "embed:") {
		// 嵌入式文件系统
		dirPath = dirPath[6:]
		dirFS = app_global.EmbedFS()
	} else {
		// 本地文件系统
		dirFS = file_util.NewLocalFS(app_global.AppDir())
	}

	return dirFS, dirPath
}

// 扫描目录获取文件列表
func _ScanDir(result *[]string, dirFS fs.ReadDirFS, path string) {
	path = strings.TrimSuffix(path, _PATH_SEPERATOR_BACKSLASH)
	entries, err := dirFS.ReadDir(path)

	if err != nil {
		panic(err)
	}

	for index := range entries {
		newPath := path + _PATH_SEPERATOR_BACKSLASH + entries[index].Name()

		if entries[index].IsDir() {
			// 递归扫描目录
			_ScanDir(result, dirFS, newPath)
		} else {
			// 添加文件路径到结果中
			*result = append(*result, newPath)
		}
	}
}

// 获取对应的压缩路径
func _GetMinSuffxPath(path string) string {
	startIndex := strings.LastIndex(path, "/") + 1
	// 不处理文件名中已经带有 ".min." 字符串的路径
	if strings.LastIndex(path, ".min.") >= startIndex {
		return path
	}

	dotIndex := strings.LastIndex(path, _PATH_SUFFIX_DOT)
	// 不处理文件名中不带有 "." 符号的路径
	if dotIndex < startIndex {
		return path
	}

	var newPath strings.Builder
	newPath.WriteString(path[0:dotIndex])
	newPath.WriteString(".min")
	newPath.WriteString(path[dotIndex:])

	return newPath.String()
}

// 拼接 URL 字符串
func _JoinUrl(baseUrl string, relativeUrl string) string {
	var newUrl strings.Builder
	newUrl.WriteString(baseUrl)

	if !strings.HasSuffix(baseUrl, _PATH_SEPERATOR_BACKSLASH) {
		newUrl.WriteString(_PATH_SEPERATOR_BACKSLASH)
	}

	if strings.HasPrefix(relativeUrl, _PATH_SEPERATOR_BACKSLASH) {
		newUrl.WriteString(relativeUrl[1:])
	} else {
		newUrl.WriteString(relativeUrl)
	}

	return newUrl.String()
}
